/*
 * Copyright (c) 2015, the DeltaSync# project. All Rights Reserved.
 * This project is a C# port of the JDeltaSync project:
 *     http://jdeltasync.googlecode.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Runtime.Serialization;
using System.Text;

#if !DONOTUSE_MimeKit
using MimeKit;
#endif

namespace PM.Net.DeltaSync {
    /**
     * Represents a message on the server.
     */
    [Serializable]
    public class Message : ISerializable {
        private string   id;
        private DateTime dateReceived;
        private long     size;
        private bool     read;
        private string   subject;
        private string   from;
        #if !DONOTUSE_MimeKit
        private bool     fromDecoded = false;
        private InternetAddress
                         fromAddress = null;        
        #endif
        private bool     hasAttachments;
        
        /**
         * Creates a new {@link Message}.
         * 
         * @param id the id.
         * @param dateReceived the {@link Date} and time when the message was 
         *        received.
         * @param size the size of the messages.
         * @param read <code>true</code> if the messages has been read, 
         *        <code>false</code> otherwise.
         * @param subject the message subject.
         * @param from the name and e-mail address of the sender.
         * @param hasAttachments <code>true</code> if the message has attachments,
         *        <code>false</code> otherwise.
         */
        public Message(string id, DateTime dateReceived, long size, bool read,
                string subject, string from, bool hasAttachments) {
            this.id             = id;
            this.dateReceived   = dateReceived.Kind == DateTimeKind.Unspecified ? dateReceived : dateReceived.ToLocalTime();
            this.size           = size;
            this.read           = read;
            this.subject        = subject;
            this.from           = from;
            this.hasAttachments = hasAttachments;
        }
    
        protected Message(SerializationInfo info, StreamingContext context) {
            #if !DONOTUSE_MimeKit
            this.fromDecoded    = false;
            #endif
            this.id             = info.GetString  ("id");
            this.dateReceived   = info.GetDateTime("dateReceived");
            this.size           = info.GetInt64   ("size");
            this.read           = info.GetBoolean ("read");
            this.subject        = info.GetString  ("subject");
            this.from           = info.GetString  ("from");
            this.hasAttachments = info.GetBoolean ("hasAttachments");
        }
        
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("id",             id);
            info.AddValue("dateReceived",   dateReceived);
            info.AddValue("size",           size);
            info.AddValue("read",           read);
            info.AddValue("subject",        subject);
            info.AddValue("from",           from);
            info.AddValue("hasAttachments", hasAttachments);
        }
        
        /**
         * Returns the id of this {@link Message}.
         * 
         * @return the id.
         */
        public string Id {
            get { return id; }
        }
    
        /**
         * Returns the {@link Date} and time when this message was received.
         * 
         * @return the {@link Date} and time.
         */
        public DateTime DateReceived {
            get { return dateReceived; }
        }
    
        /**
         * Returns the size of this {@link Message} in bytes.
         * 
         * @return the size.
         */
        public long Size {
            get { return size; }
        }
    
        /**
         * Returns whether this {@link Message} has been read.
         * 
         * @return <code>true</code> if the messages has been read, 
         *         <code>false</code> otherwise.
         */
        public bool IsRead {
            get { return read; }
        }
    
        /**
         * Returns whether this {@link Message} has attachments.
         * 
         * @return <code>true</code> if the messages has attachments, 
         *         <code>false</code> otherwise.
         */
        public bool HasAttachments {
            get { return hasAttachments; }
        }
        
        /**
         * Returns the subject of this {@link Message}.
         * 
         * @return the subject.
         */
        #if !DONOTUSE_MimeKit
        public string OriginalSubject {
            get { return subject; }
        }
        public string Subject {
            get { return MimeKit.Utils.Rfc2047.DecodePhrase(Encoding.ASCII.GetBytes(this.subject)); }
        }
        #else
        public string Subject {
            get { return subject; }
        }
        #endif
    
        /**
         * Returns the name and e-mail address of the person who sent this 
         * {@link Message}.
         * 
         * @return the sender name and e-mail.
         */
        #if !DONOTUSE_MimeKit
        public InternetAddress FromAddress {
            get {
                if (!fromDecoded) {
                    try {
                        fromAddress = string.IsNullOrEmpty(this.from) ? null : InternetAddress.Parse(this.from);
                    } catch (MimeKit.ParseException) {
                        if (IsEmptyAddress(this.from))
                            fromAddress = null;
                        else
                            throw;
                    }
                    fromDecoded = true;
                }
                return fromAddress;
            }
        }
        
        public string OriginalFrom {
            get { return from; }
        }
        public string From {
            get { 
                var fa = this.FromAddress;
                return fa == null ? null : fa.ToString();
            }
        }        
        
        private static bool IsEmptyAddress(string address) {
            if (string.IsNullOrEmpty(address))
                return true;
            if (!address.EndsWith("<>"))
                return false;
            address = address.Substring(0, address.Length - 2).TrimEnd();
            return address.Length == 0 || address == "\"\"";
        }
        #else
        public string From {
            get { return from; }
        }        
        #endif
        
        public override string ToString() {
            return id;
            /*StringBuilder sb = new StringBuilder(base.ToString() + "(");
            sb.Append("id").Append("=").Append(id).Append(",");
            sb.Append("dateReceived").Append("=").Append(dateReceived).Append(",");
            sb.Append("size").Append("=").Append(size).Append(",");
            sb.Append("read").Append("=").Append(read).Append(",");
            sb.Append("subject").Append("=").Append(subject).Append(",");
            sb.Append("from").Append("=").Append(from).Append(",");
            sb.Append("has attachments").Append("=").Append(hasAttachments);
            sb.Append(")");
            return sb.ToString();*/
        }
    }
}